#ifndef SIMPLE_SUPPORT_ALGORITHM_COPY_HPP
#define SIMPLE_SUPPORT_ALGORITHM_COPY_HPP

#include <utility> // std::pair std::move

#include "traits.hpp" // iterable
#include "adl_helper.hpp" // adl_helper::adl_begin adl_helper::adl_end
#include "reaches.hpp" // reaches sequence

namespace simple::support
{

	// you can duplicate a pattern from a beginning of a range via a single copy
	// copy_n(pattern_begin, num_copies * pattern_size, pattern_end)
	// this comes up in lz77 decompression
	// unfortunately std is too clever for that (order not guaranteed)
	// threw in 'reaches' abstraction as well

	template <typename I, typename E, typename O>
	constexpr std::pair<I,O> copy(I i, E i_end, O o)
	{
		for(; not reaches(i, i_end); ++i, ++o)
			*o = *i;
		return {std::move(i), std::move(o)};
	}

	template <typename I, typename O>
	constexpr std::pair<I,O> copy_n(I i, std::size_t n, O o)
	{
		for(; n --> 0; ++i, ++o)
			*o = *i;
		return {std::move(i), std::move(o)};
	}

	// TODO: conflicts with copy in range_wrappers.hpp
	// similar situation with find.hpp, but too lazy to update use cases rn
	// current use case for the copy above is a move only input iterator, so gotta support that here as well
	// template <typename Range, typename OutIt,
	// 	std::enable_if_t<is_range_v<Range>>* = nullptr>
	// constexpr auto copy(const Range& range, OutIt out)
	// {
	// 	return support::copy(adl_helper::adl_begin(range), adl_helper::adl_end(range), out);
	// }

	// TODO: rename the above to repeat as well
	constexpr auto repeat(iterable auto i, sequence auto r)
	{
		auto o = adl_helper::adl_begin(r);
		auto o_end = adl_helper::adl_end(r);
		for(; not reaches(o, o_end); ++i, ++o)
			*o = *i;
		return std::pair{std::move(i), std::move(o)};
	}

} // namespace simple::support

#endif /* end of include guard */
